/**
 * 工具包功能实现
 */

#ifdef _WIN32
	#define _CRT_SECURE_NO_WARNINGS
	#include <windows.h>
    #include <minwindef.h>
    #include <debugapi.h>
	#include <time.h>       // for time(), CLOCK_REALTIME
#endif

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include "utils.h"

 // 调试用的标志
static size_t _dbgflags = 0;

void dbgflag_set(unsigned int idx, bool val) {
	if (idx >= sizeof(_dbgflags) * 8) return;
	if (val) { _dbgflags |= (((size_t)1) << idx); return; }
	_dbgflags &= ~(((size_t)1) << idx);
}

bool dbgflag_get(unsigned int idx) {
	if (idx >= sizeof(_dbgflags) * 8) return 0;
	return (_dbgflags >> idx) & 1;
}

void dbgbreak() {
#ifdef _WIN32
    DebugBreak();
#elif (__linux__ || __unix__)
    __builtin_trap();
#else // vitis ?
    // not support ?
#endif
}

int version_compare(version_t* ver1, version_t* ver2) {
	if(ver1->dw > ver2->dw) {
		return 1;
	} else if(ver1->dw < ver2->dw) {
		return -1;
	} else {
		return 0;
	}
}

size_t align(size_t addr, size_t nbytes) {
	size_t mask = nbytes - 1;
	return (addr & mask) ? (addr + nbytes) & (~mask) : addr;
}

size_t memcpy_to_aligned32(void *dst32, const void *_src, size_t _size) {
	if(!dst32 || !_src || !_size) return 0;
	uint64_t addr = (uint64_t)(uintptr_t)dst32;
	size_t size = _size;
	const uint8_t *src = (const uint8_t*)_src;

	// 如果起始位置未 uint32_t 对齐，则先写入未对齐部分数据
	uint32_t residue = addr % 4;
	if(residue) {
		size_t nfill = 4 - residue; // 未对齐的字节数
		if(size < nfill) nfill = size; // 需要补齐的字节数
		addr &= 0xFFFFFFFFFFFFFFFC;
		uint32_t reg = *((uint32_t*)(uintptr_t)addr);
		if(nfill >= 1) ((char*)&reg)[residue + 0] = ((char*)src)[0];
		if(nfill >= 2) ((char*)&reg)[residue + 1] = ((char*)src)[1];
		if(nfill >= 3) ((char*)&reg)[residue + 2] = ((char*)src)[2];
		*((uint32_t*)(uintptr_t)addr) = reg;
		addr += 4; src += nfill; size -= nfill;
	}

	// 写入 uint32_t 对齐部分数据
	size_t nreg = size / 4;
	for(size_t i=0; i < nreg; i++, addr += 4, src += 4) {
		*((uint32_t*)(uintptr_t)addr) = *((uint32_t*)src);
	}

	// 如果结束位置未 uint32_t 对齐，则写入未对齐部分数据
	residue = (uint32_t)(size - nreg * 4); // 需要补齐的字节数
	if(residue) {
		uint32_t reg = *((uint32_t*)(uintptr_t)addr);
		if(residue >= 1) ((char*)&reg)[0] = ((char*)src)[0];
		if(residue >= 2) ((char*)&reg)[1] = ((char*)src)[1];
		if(residue >= 3) ((char*)&reg)[2] = ((char*)src)[2];
		*((uint32_t*)(uintptr_t)addr) = reg;
	}

	return _size;
}

size_t memcpy_from_aligned32(void *_dst, const void *src32, size_t _size) {
	if(!_dst || !src32 || !_size) return 0;
	uint64_t addr = (uint64_t)(uintptr_t)src32;
	size_t size = _size;
	const uint8_t *dst = (const uint8_t*)_dst;

	// 如果起始位置未 uint32_t 对齐，则先写入未对齐部分数据
	uint32_t residue = addr % 4;
	if(residue) {
		size_t nfill = 4 - residue; // 未对齐的字节数
		if(size < nfill) nfill = size; // 需要补齐的字节数
		addr &= 0xFFFFFFFFFFFFFFFC;
		uint32_t reg = *((uint32_t*)(uintptr_t)addr);
		if(nfill >= 1) ((char*)dst)[0] = ((char*)&reg)[residue + 0];
		if(nfill >= 2) ((char*)dst)[1] = ((char*)&reg)[residue + 1];
		if(nfill >= 3) ((char*)dst)[2] = ((char*)&reg)[residue + 2];
		addr += 4; dst += nfill; size -= nfill;
	}

	// 写入 uint32_t 对齐部分数据
	size_t nreg = size / 4;
	for(size_t i=0; i < nreg; i++, addr += 4, dst += 4) {
		*((uint32_t*)dst) = *((uint32_t*)(uintptr_t)addr);
	}

	// 如果结束位置未 uint32_t 对齐，则写入未对齐部分数据
	residue = (uint32_t)(size - nreg * 4); // 需要补齐的字节数
	if(residue) {
		uint32_t reg = *((uint32_t*)(uintptr_t)addr);
		if(residue >= 1) ((char*)dst)[0] = ((char*)&reg)[0];
		if(residue >= 2) ((char*)dst)[1] = ((char*)&reg)[1];
		if(residue >= 3) ((char*)dst)[2] = ((char*)&reg)[2];
	}

	return _size;
}

size_t memcpy_to_aligned64(void *dst64, const void *_src, size_t _size) {
	if(!dst64 || !_src || !_size) return 0;
	uint64_t addr = (uint64_t)(uintptr_t)dst64;
	size_t size = _size;
	const uint8_t *src = (const uint8_t*)_src;

	// 如果起始位置未 uint64_t 对齐，则先写入未对齐部分数据
	uint32_t residue = addr % 8;
	if(residue) {
		size_t nfill = 4 - residue; // 未对齐的字节数
		if(size < nfill) nfill = size; // 需要补齐的字节数
		addr &= 0xFFFFFFFFFFFFFFFC;
		uint64_t reg = *((uint64_t*)(uintptr_t)addr);
		if(nfill >= 1) ((char*)&reg)[residue + 0] = ((char*)src)[0];
		if(nfill >= 2) ((char*)&reg)[residue + 1] = ((char*)src)[1];
		if(nfill >= 3) ((char*)&reg)[residue + 2] = ((char*)src)[2];
		if(nfill >= 4) ((char*)&reg)[residue + 3] = ((char*)src)[3];
		if(nfill >= 5) ((char*)&reg)[residue + 4] = ((char*)src)[4];
		if(nfill >= 6) ((char*)&reg)[residue + 5] = ((char*)src)[5];
		if(nfill >= 7) ((char*)&reg)[residue + 6] = ((char*)src)[6];
		*((uint64_t*)(uintptr_t)addr) = reg;
		addr += 8; src += nfill; size -= nfill;
	}

	// 写入 uint64_t 对齐部分数据
	size_t nreg = size / 8;
	for(size_t i=0; i < nreg; i++, addr += 8, src += 8) {
		*((uint64_t*)(uintptr_t)addr) = *((uint64_t*)src);
	}

	// 如果结束位置未 uint64_t 对齐，则写入未对齐部分数据
	residue = (uint32_t)(size - nreg * 8); // 需要补齐的字节数
	if(residue) {
		uint64_t reg = *((uint64_t*)(uintptr_t)addr);
		if(residue >= 1) ((char*)&reg)[0] = ((char*)src)[0];
		if(residue >= 2) ((char*)&reg)[1] = ((char*)src)[1];
		if(residue >= 3) ((char*)&reg)[2] = ((char*)src)[2];
		if(residue >= 4) ((char*)&reg)[3] = ((char*)src)[3];
		if(residue >= 5) ((char*)&reg)[4] = ((char*)src)[4];
		if(residue >= 6) ((char*)&reg)[5] = ((char*)src)[5];
		if(residue >= 7) ((char*)&reg)[6] = ((char*)src)[6];
		*((uint64_t*)(uintptr_t)addr) = reg;
	}

	return _size;
}

size_t memcpy_from_aligned64(void *_dst, const void *src64, size_t _size) {
	if(!_dst || !src64 || !_size) return 0;
	uint64_t addr = (uint64_t)(uintptr_t)src64;
	size_t size = _size;
	const uint8_t *dst = (const uint8_t*)_dst;

	// 如果起始位置未 uint64_t 对齐，则先写入未对齐部分数据
	uint32_t residue = addr % 8;
	if(residue) {
		size_t nfill = 8 - residue; // 未对齐的字节数
		if(size < nfill) nfill = size; // 需要补齐的字节数
		addr &= 0xFFFFFFFFFFFFFFFC;
		uint64_t reg = *((uint64_t*)(uintptr_t)addr);
		if(nfill >= 1) ((char*)dst)[0] = ((char*)&reg)[residue + 0];
		if(nfill >= 2) ((char*)dst)[1] = ((char*)&reg)[residue + 1];
		if(nfill >= 3) ((char*)dst)[2] = ((char*)&reg)[residue + 2];
		if(nfill >= 4) ((char*)dst)[3] = ((char*)&reg)[residue + 3];
		if(nfill >= 5) ((char*)dst)[4] = ((char*)&reg)[residue + 4];
		if(nfill >= 6) ((char*)dst)[5] = ((char*)&reg)[residue + 5];
		if(nfill >= 7) ((char*)dst)[6] = ((char*)&reg)[residue + 6];
		addr += 8; dst += nfill; size -= nfill;
	}

	// 写入 uint64_t 对齐部分数据
	size_t nreg = size / 8;
	for(size_t i=0; i < nreg; i++, addr += 8, dst += 8) {
		*((uint64_t*)dst) = *((uint64_t*)(uintptr_t)addr);
	}

	// 如果结束位置未 uint64_t 对齐，则写入未对齐部分数据
	residue = (uint32_t)(size - nreg * 8); // 需要补齐的字节数
	if(residue) {
		uint64_t reg = *((uint64_t*)(uintptr_t)addr);
		if(residue >= 1) ((char*)dst)[0] = ((char*)&reg)[0];
		if(residue >= 2) ((char*)dst)[1] = ((char*)&reg)[1];
		if(residue >= 3) ((char*)dst)[2] = ((char*)&reg)[2];
		if(residue >= 4) ((char*)dst)[3] = ((char*)&reg)[3];
		if(residue >= 5) ((char*)dst)[4] = ((char*)&reg)[4];
		if(residue >= 6) ((char*)dst)[5] = ((char*)&reg)[5];
		if(residue >= 7) ((char*)dst)[6] = ((char*)&reg)[6];
	}

	return _size;
}


size_t count_bit1(size_t num) {
    size_t cnt = 0;
	for(int i = (sizeof(num)*8 - 1); i >= 0; i--) {
		if((num >> i) & 0x01) cnt++;
	}
	return cnt;
}

size_t count_hex(size_t num) {
	for(int i = (sizeof(num)*8 - 1); i >= 0; i--) {
		if((num >> (i*4)) & 0x0F) return i + 1;
	}
	return 0;
}

/* HEX 字符表 */
static const char HEXCHAR[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

const char* to_hex(size_t num, size_t width) {
    static char buf[17];
    char *ch = buf;
    
    if(width <  1) return "";
    if(width > 16) width = 16;
    for(int i = (int)(width - 1); i >= 0; i--) {
        *(ch++) = HEXCHAR[(num >> (i*4)) & 0x0F];
    }

    *ch = '\0';
    return buf;
}

char* bytes_to_hexstr(const uint8_t* bytes, int start, int len, char* gap, char *hexbuf, int hexBufLen) {
    if(!bytes || (start < 0) || (len < 1)) { return NULL; }

    uint8_t ch;
    int pos = 0;
    int gaplen = gap ? (int)strlen(gap) : 0;
	
	// 判断缓冲区长度是否够
	if(len*2 + (len-1)*gaplen + 1 > hexBufLen) { return NULL; }

    for(int i=0; i < len; i++) {
        // 一个字节转换为2个字符
        ch = bytes[start+i];
        hexbuf[pos++] = HEXCHAR[(ch >> 4) & 0x0F];
        hexbuf[pos++] = HEXCHAR[ch & 0x0F];

        // 添加分隔符
        if(gaplen && i < len-1) for(int j=0; j<gaplen; j++) { hexbuf[pos++] = gap[j]; }
    }
    hexbuf[pos++] = '\0';

    return hexbuf;
}

// 如果 ch 是一个正确的 HEX 字符，则返回其值(4bit)；否则返回-1
static signed char _hexval(char ch) {
	if(ch >= '0' && ch <= '9') { return ch - '0'; }
	if(ch >= 'a' && ch <= 'f') { return ch - 'a' + 10; }
	if(ch >= 'A' && ch <= 'F') { return ch - 'A' + 10; }
	return -1;
}

int hexstr_to_bytes(const char *hexBuf, uint8_t* bytes, int len) {
    if(!hexBuf || !bytes || !len) { return -1; }
	
	int ret = 0;		// 转换后的长度
	uint8_t bt = 0;			// 当前 byte
	bool l4 = false;	// bt 中是否已经有低 4 位
	signed char ch;		// 当前 HEX 字符代表的 4 位数值
	
	for(; *hexBuf; hexBuf++) {
		ch = _hexval(*hexBuf);
		if(ch >= 0) {
			if(l4) {
				if(ret+1 > len) { return -1; }
				bytes[ret++] = (bt << 4 | ch); l4 = false;
			} else {
				bt = ch; l4 = true;
			}
		} else {
			if(l4) {
				if(ret+1 > len) { return -1; }
				bytes[ret++] = bt; l4 = false;
			} else {
				continue; 
			}
		}
	}
	return ret;
}

// 注意：此函数非线程安全！下一次调用会覆盖上一次的调用！
char* mac_to_hexstr(const void *_mac, char ch) {
	uint8_t *mac = (uint8_t*)_mac;
	if(!mac) { return NULL; }
	static char buf[18];
	char gap[] = {ch, 0};
	ch ? bytes_to_hexstr(mac, 0, 6, gap, buf, 18) : bytes_to_hexstr(mac, 0, 6, NULL, buf, 18);
	buf[17] = '\0';
	return buf;
}

bool mac_match(const void *mac1, const void *mac2) {
	return mac1 && mac2 && (memcmp(mac1, mac2, 6) == 0);
}

uint8_t* reverse_bytes(uint8_t *bytes, int len) {
	if(!bytes || !len) { return NULL; }
	uint8_t ch;
	for(int i=0; i<len/2; i++) {
		ch = bytes[i];
		bytes[i] = bytes[len-1-i];
		bytes[len-1-i] = ch;
	}
	return bytes;
}

void* reverse_memcpy(void *dst, const void *src, size_t len) {
	for(; len > 0; len--) {
		((uint8_t*)dst)[len-1] = ((uint8_t*)src)[len-1];
	}
	return dst;
}

uint8_t hexdec2int(uint8_t hexdec) {
	return ((hexdec >> 4) & 0x0F) * 10 + (hexdec & 0x0F);
}

uint8_t int2hexdec(uint8_t ch) {
	return (((ch/10) & 0x0F) << 4) | (ch%10);
}


uint32_t nrand(uint32_t n) {
	return (uint32_t)((1.0*rand()/0xFFFFFFFF)*n);
}

uint32_t xrand(uint32_t n1, uint32_t n2) {
	return (n1 + nrand(n2-n1));
}


#define PUTS(_str) do { char *str = (char*)_str; while(*str) user_putchar(*(str++)); } while(0)

void dumpbin(const void *buf, size_t len, size_t cpl, long offset, bool show_ascii, user_putchar_t user_putchar) {
    if(!buf || !len) return;
    size_t l, i, pos;
    size_t lc = len/cpl + ((len%cpl) ? 1:0);   // lines count
    const unsigned char *data = (const unsigned char*)buf;
    unsigned char ch;
	size_t offset_width = count_hex(offset + len);
	if(!user_putchar) user_putchar = putchar;

    // 逐行输出
    for(l=0; l<lc; l++) {
        pos = l*cpl;

        // 行首打印偏移地址
        if(offset >= 0) {
            PUTS(to_hex((pos + offset), offset_width));
            PUTS(": ");
        }

        // 打印十六进制
        for(i=0; i<cpl; i++) {
            if(pos < len) {
                PUTS(to_hex(data[pos], 2));
                PUTS(" ");
            } else {
            	PUTS("   ");
            }
            pos++;
        }

        pos = l*cpl;

        // 打印字符
        if(show_ascii) {
			for(i=0; i<cpl; i++) {
				ch = data[pos++];
				user_putchar((ch < 0x20 || ch > 0x7F) ? '.' : ch);
				if(pos >= len) break;
			}
        }

        PUTS("\r\n");
    }
}

uint32_t sum_bytes(const void* data, size_t len) {
    uint32_t sum = 0;
    for(uint32_t i=0; i < len; i++) sum += ((uint8_t*)data)[i];
    return sum;
}


#ifdef _WIN32

const char* get_windows_error_msg() {
    static char msg_buffer[256];
    DWORD err = GetLastError();
    DWORD len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)msg_buffer, sizeof(msg_buffer), NULL);
    if (!len) {
        snprintf(msg_buffer, sizeof(msg_buffer), "%d - Unknown error (FormatMessage() failed with code: %d)", err, GetLastError());
    }
    return msg_buffer;
}

BYTE* allocate_buffer(size_t size, size_t alignment) {
    if (size == 0) return NULL;
    if (alignment == 0) {
        SYSTEM_INFO sys_info;
        GetSystemInfo(&sys_info);
        alignment = sys_info.dwPageSize;
    }
    printf("Allocating host-side buffer of size %llu, aligned to %llu bytes\n", size, alignment);
    return (BYTE*)_aligned_malloc(size, alignment);
}

char* wchar_to_char(const wchar_t* wstr, unsigned int cp) {
    static char buf[512];
    int len = WideCharToMultiByte(cp, 0, wstr, (int)wcslen(wstr), buf, sizeof(buf)-1, NULL, NULL);
    buf[len] = '\0';
    return buf;
}

typedef struct {
    unsigned long process_id;
    HWND best_handle;
} handle_data;

static BOOL IsMainWindow(HWND handle) {
    return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}

static BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) {
    handle_data* data = (handle_data*)lParam;
    unsigned long process_id = 0;
    GetWindowThreadProcessId(handle, &process_id);
    if (data->process_id == process_id || IsMainWindow(handle)) {
        data->best_handle = handle;
        return FALSE;
    }
    return TRUE;
}

void* find_main_window(unsigned long process_id) {
    handle_data data;
    data.process_id = process_id;
    data.best_handle = 0;
    EnumWindows(EnumWindowsCallback, (LPARAM)&data);
    return data.best_handle;
}

void* find_current_process_main_window() {
    return find_main_window(GetCurrentProcessId());
}

void* find_sibling_window(void* parent, const char *clazz, const char *title) {
    if (!parent) parent = FindWindowA(clazz, title);
    // clazz 和 title 不能同时为空
    if (!parent || ((!clazz || !strlen(clazz)) && (!title || !strlen(title)))) return NULL;
    
    HWND hwin = NULL;
    while (1) {
        if (hwin = FindWindowExA(parent, hwin, clazz, title)) {
            return hwin;
        }
    }

    return NULL;
}

size_t console_read_key(size_t wait_timeout_ms) {
    // 取得当前 stdin 对应的 handle
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
    if(hStdin == INVALID_HANDLE_VALUE) return 0;

    // 取得 console 的输入事件数量
    while(1) {
        DWORD len = 0;
        BOOL ret = GetNumberOfConsoleInputEvents(hStdin, &len);
        if (!ret) return 0;
        if (len) return len;
        if (!wait_timeout_ms) return 0;
        Sleep(1);
        wait_timeout_ms--;
    }
}

#endif
